﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace Bamboo.Utils
{
    public class SerializeFieldInfo
    {
        public Type EntityType;
        public MemberInfo MemberInfo;
        public FieldInfo FieldInfo;
        public PropertyInfo PropertyInfo;
        /// <summary>
        /// 展示名称
        /// </summary>
        public string DisplayName;
        /// <summary>
        /// 展示列宽，只有部分文档格式支持这个属性。对于excel来说单位是“字宽”，对于HTML表格来说单位是“px”。
        /// null或取值为0代表未设置。
        /// </summary>
        public int Width;

        public bool IsNumericType = false;
        /// <summary>
        /// 实际列序号，由使用方自己赋值
        /// </summary>
        public int RealColumnIndex = -1;

        public Type FieldType()
        {
            if (FieldInfo != null) return FieldInfo.FieldType;
            else return PropertyInfo.PropertyType;
        }

        public bool CanRead()
        {
            if (this.PropertyInfo == null)
            {
                return true;
            }
            else
            {
                return this.PropertyInfo.CanRead;
            }
        }

        public bool CanWrite()
        {
            if (this.PropertyInfo == null)
            {
                return true;
            }
            else
            {
                return this.PropertyInfo.CanWrite;
            }
        }

        public string Name()
        {
            if (string.IsNullOrWhiteSpace(DisplayName))
            {
                return this.MemberInfo.Name;
            }
            else
            {
                return this.DisplayName;
            }
        }

        public void SetValue(object obj, object value)
        {
            if (this.PropertyInfo == null)
            {
                this.FieldInfo.SetValue(obj, value);
            }
            else
            {
                this.PropertyInfo.SetValue(obj, value);
            }
        }
        /// <summary>
        /// 自动将文本转成本字段类型，然后赋值到对象
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="valueText"></param>
        /// <exception cref="Exception"></exception>
        public void SetText(object entity, string valueText)
        {
            var fieldType = this.FieldType();
            if (fieldType == typeof(string))
            {
                SetValue(entity, valueText);
            }
            else if (fieldType == typeof(int))
            {
                int vint;
                if (int.TryParse(valueText, out vint))
                {
                    SetValue(entity, vint);
                }
                else
                {
                    SetValue(entity, (int)0);
                }
            }
            else if (fieldType == typeof(uint))
            {
                uint vint;
                if (uint.TryParse(valueText, out vint))
                {
                    SetValue(entity, vint);
                }
                else
                {
                    SetValue(entity, (uint)0);
                }
            }
            else if (fieldType == typeof(Int64))
            {
                Int64 vint;
                if (Int64.TryParse(valueText, out vint))
                {
                    SetValue(entity, vint);
                }
                else
                {
                    SetValue(entity, (Int64)0);
                }
            }
            else if (fieldType == typeof(double))
            {
                double vint;
                if (double.TryParse(valueText, out vint))
                {
                    SetValue(entity, vint);
                }
                else
                {
                    SetValue(entity, (double)0);
                }
            }
            else if (fieldType == typeof(bool))
            {
                string valueLower = valueText.ToLower();
                if (valueText == "是" || valueText == "1" || valueLower == "y" || valueLower == "true")
                {
                    SetValue(entity, true);
                }
                else
                {
                    SetValue(entity, false);
                }
            }
            else if (fieldType.BaseType == typeof(Enum))
            {
                try
                {
                    Enum value = (Enum)Enum.Parse(fieldType, valueText, true);
                    SetValue(entity, value);
                }
                catch (Exception) { }
            }
            else
            {
                throw new Exception("不支持该字段[" + Name() + "]类型[" + fieldType.Name + "]的解析");
            }
        }

        public object GetValue(object obj)
        {
            if (this.PropertyInfo == null)
            {
                return this.FieldInfo.GetValue(obj);
            }
            else
            {
                return this.PropertyInfo.GetValue(obj);
            }
        }

        public static List<SerializeFieldInfo> Parse(Type t)
        {
            var list = new List<SerializeFieldInfo>();
            foreach (var member in t.GetMembers())
            {
                SerializeFieldInfo item = null;
                if (member.MemberType == MemberTypes.Property)
                {
                    item = new SerializeFieldInfo();
                    item.PropertyInfo = t.GetProperty(member.Name);
                }
                else if (member.MemberType == MemberTypes.Field)
                {
                    item = new SerializeFieldInfo();
                    item.FieldInfo = t.GetField(member.Name);
                }
                else
                {
                    continue;
                }
                item.EntityType = t;
                item.MemberInfo = member;
                var attributes = item.MemberInfo.GetCustomAttributes(true);
                foreach (var attribute in attributes)
                {
                    if (attribute is DisplayNameAttribute)
                        item.DisplayName = (attribute as DisplayNameAttribute).DisplayName;
                    else if (attribute is ColumnWidthAttribute)
                        item.Width = (attribute as ColumnWidthAttribute).Value;
                }
                if (item.DisplayName == null) continue;
                string fieldtype = item.FieldType().Name.ToLower();
                item.IsNumericType = fieldtype == "int" || fieldtype == "int16" || fieldtype == "int32" ||
                    fieldtype == "int64" || fieldtype == "double" || fieldtype == "decimal" || fieldtype == "uint" ||
                    fieldtype == "uint16" || fieldtype == "uint32" || fieldtype == "uint64";
                list.Add(item);
            }
            return list;
        }
    }
}
